package com.hkd.system.service.exam.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.hkd.common.core.constants.Constants;
import com.hkd.common.core.domain.R;
import com.hkd.common.core.domain.TableDataInfo;
import com.hkd.common.core.enums.ResultCode;
import com.hkd.common.security.exception.ServiceException;
import com.hkd.system.domain.exam.Exam;
import com.hkd.system.domain.exam.ExamQuestion;
import com.hkd.system.domain.exam.dto.ExamAddDTO;
import com.hkd.system.domain.exam.dto.ExamEditDTO;
import com.hkd.system.domain.exam.dto.ExamQueryDTO;
import com.hkd.system.domain.exam.dto.ExamQuestAddDTO;
import com.hkd.system.domain.exam.vo.ExamDetailVO;
import com.hkd.system.domain.exam.vo.ExamVO;
import com.hkd.system.domain.question.Question;
import com.hkd.system.domain.question.vo.QuestionVO;
import com.hkd.system.manager.ExamCacheManager;
import com.hkd.system.mapper.exam.ExamMapper;
import com.hkd.system.mapper.exam.ExamQuestionMapper;
import com.hkd.system.mapper.question.QuestionMapper;
import com.hkd.system.service.exam.IExamService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.hkd.common.core.controller.BaseController.getTableDataInfo;
@Slf4j
@Service
public class ExamServiceImpl extends ServiceImpl<ExamQuestionMapper, ExamQuestion> implements IExamService {
    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ExamQuestionMapper examQuestionMapper;

    @Autowired
    private ExamCacheManager examCacheManager;

    @Override
    public TableDataInfo list(ExamQueryDTO examQueryDto) {
        //分页查询
        PageHelper.startPage(examQueryDto.getPageNum(), examQueryDto.getPageSize());
        //查询数据
        List<ExamVO> examVOList = examMapper.selectExamList(examQueryDto);

        return getTableDataInfo(examVOList);
    }

    @Override
    public R add(ExamAddDTO examAddDTO) {
        checkExamSaveParams(examAddDTO ,null);
        //新增数据
        Exam exam = new Exam();
        BeanUtil.copyProperties(examAddDTO, exam);
        int insert = examMapper.insert(exam);
        if(insert <= 0){
            //新增失败
            log.error("新增考试失败");
            return R.failed(ResultCode.FAILED_EXAM_ADD);
        }
        return R.success(exam.getExamId().toString());
    }

    private void checkExamSaveParams(ExamAddDTO examSaveDTO,Long examId) {
        //参数校验
        if(examSaveDTO.getStartTime().isBefore(LocalDateTime.now()) ||
                examSaveDTO.getStartTime().isAfter(examSaveDTO.getEndTime()) ||
                examSaveDTO.getEndTime().isEqual(examSaveDTO.getStartTime())
        ){
            log.error("竞赛时间异常");
            throw new ServiceException(ResultCode.FAILED_EXAM_ADD_TIME);
        }
        //名称不能重复
        List<Exam> examList = examMapper
                .selectList(new LambdaQueryWrapper<Exam>()
                        .eq(Exam::getTitle, examSaveDTO.getTitle())
                        .ne(examId != null, Exam::getExamId, examId));
        if (CollectionUtil.isNotEmpty(examList)) {
            throw new ServiceException(ResultCode.FAILED_ALREADY_EXISTS);
        }
    }

    @Override
    public R questionAdd(ExamQuestAddDTO examQuestAddDTO) {
        //校验题目是否存在
        Exam exam = examMapper.selectById(examQuestAddDTO.getExamId());
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_ADD);
        }
        Set<Long> questionIdSet = examQuestAddDTO.getQuestionIdSet();
        if(CollectionUtils.isEmpty(questionIdSet)){
            return R.failed(ResultCode.FAILED_EXAM_AddDTO);
        }
        //校验题目是否存在
        List<Question> questionList = questionMapper.selectBatchIds(questionIdSet);
        if(CollectionUtils.isEmpty(questionList)|| questionList.size() < questionIdSet.size()){
            log.error("题目不存在");
            return R.failed(ResultCode.FAILED_EXAM_QUESTION);
        }
        boolean result = saveExamQuestion(questionIdSet, exam);
        if(!result){
            log.error("竞赛题目添加失败");
            return R.failed(ResultCode.FAILED_EXAM_ADD);
        }
        return R.success();
    }

    @Override
    public R detail(Long examId) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //存入竞赛信息
        ExamDetailVO examDetailVO = new ExamDetailVO();
        BeanUtil.copyProperties(exam,examDetailVO);
        //2.查询竞赛题目信息
        List<ExamQuestion> examQuestionList = examQuestionMapper.selectList(new LambdaQueryWrapper<ExamQuestion>()
                .select(ExamQuestion::getQuestionId)
                .eq(ExamQuestion::getExamId, examId)
                .orderByAsc(ExamQuestion::getQuestionOrder));
        if(CollectionUtils.isEmpty(examQuestionList)){
            log.error("竞赛题目不存在");
            return R.success(examDetailVO);
        }
        //查询题目信息
        List<Long> questionIdList = examQuestionList.stream().map(ExamQuestion::getQuestionId).toList();
        //select * from tb_question question_id in (1,2,3)
        List<Question> questionList = questionMapper.selectList(new LambdaQueryWrapper<Question>()
                .select(Question::getQuestionId, Question::getTitle, Question::getDifficulty)
                .in(Question::getQuestionId, questionIdList));
        //校验查询结果
        if(CollectionUtils.isEmpty(questionList)){
            log.error("题目查询失败");
            return R.failed(ResultCode.FAILED_EXAM_QUESTION_NOT_EXISTS);
        }
        //3.添加题目信息
        List<QuestionVO> questionVOList = BeanUtil.copyToList(questionList, QuestionVO.class);
        examDetailVO.setExamQuestionsList(questionVOList);
        return R.success(examDetailVO);
    }

    @Override
    public R edit(ExamEditDTO examEditDTO) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examEditDTO.getExamId());
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //参数校验
        checkExamSaveParams(examEditDTO, examEditDTO.getExamId());
        //2.修改竞赛信息
        exam.setTitle(examEditDTO.getTitle());
        exam.setStartTime(examEditDTO.getStartTime());
        exam.setEndTime(examEditDTO.getEndTime());
        int update = examMapper.updateById(exam);
        if(update <= 0){
            log.error("修改竞赛失败");
            return R.failed(ResultCode.FAILED_EXAM_ADD);
        }
        return R.success();
    }

    @Override
    public R questionDelete(Long examId, Long questionId) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //时间判断
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            log.error("竞赛已开始，不能删除题目");
            return R.failed(ResultCode.FAILED_EXAM_HAS_START);
        }
        //2.删除题目
        int delete = examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId)
                .eq(ExamQuestion::getQuestionId, questionId));
        if(delete <= 0){
            log.error("删除题目失败");
            return R.failed(ResultCode.FAILED_EXAM_DELETE);
        }
        return R.success();
    }

    @Override
    public R delete(Long examId) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //时间判断
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            log.error("竞赛已开始，不能删除题目");
            return R.failed(ResultCode.FAILED_EXAM_HAS_START);
        }
        //2.删除竞赛
        int delete = examMapper.deleteById(examId);
        if(delete <= 0){
            log.error("删除题目失败");
            return R.failed(ResultCode.FAILED_EXAM_DELETE);
        }
        //题目为空无所谓
        examQuestionMapper.delete(new LambdaQueryWrapper<ExamQuestion>()
                .eq(ExamQuestion::getExamId, examId));

        return R.success();
    }

    @Override
    public R publish(Long examId) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //2.竞赛是否存在题目
        Long count = examQuestionMapper.selectCount(new LambdaQueryWrapper<ExamQuestion>().eq(ExamQuestion::getExamId, examId));
        if(count == null || count <= 0){
            log.error("竞赛题目不存在");
            return R.failed(ResultCode.FAILED_EXAM_QUESTION_NOT_EXISTS);
        }
        //3.是否开赛
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            log.error("竞赛已开始，不能发布目");
            return R.failed(ResultCode.FAILED_EXAM_HAS_START);
        }
        //4.修改竞赛状态
        exam.setStatus(Constants.TRUE);
        int update = examMapper.updateById(exam);
        if(update <= 0){
            log.error("修改竞赛状态失败");
            return R.failed(ResultCode.FAILED_EXAM_PUBLISH);
        }
        //5.存入redis ksy: r:t:l    value: e:d:examId
        examCacheManager.addCache(exam);

        return R.success();
    }

    @Override
    public R cancelPublish(Long examId) {
        //1.查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if(exam == null){
            log.error("竞赛不存在");
            return R.failed(ResultCode.FAILED_EXAM_NOT_EXISTS);
        }
        //2.竞赛是否存在题目
        Long count = examQuestionMapper.selectCount(new LambdaQueryWrapper<ExamQuestion>().eq(ExamQuestion::getExamId, examId));
        if(count == null || count <= 0){
            log.error("竞赛题目不存在");
            return R.failed(ResultCode.FAILED_EXAM_QUESTION_NOT_EXISTS);
        }
        //3.是否开赛
        if(exam.getStartTime().isBefore(LocalDateTime.now())){
            log.error("竞赛已开始，不能删除题目");
            return R.failed(ResultCode.FAILED_EXAM_HAS_START);
        }
        //4.修改竞赛状态
        exam.setStatus(Constants.FALSE);
        int update = examMapper.updateById(exam);
        if(update <= 0){
            log.error("修改竞赛状态失败");
            return R.failed(ResultCode.FAILED_EXAM_PUBLISH);
        }
        //5.删除redis ksy: r:t:l    value: e:d:examId
        examCacheManager.deleteCache(examId);

        return R.success();
    }


    private boolean saveExamQuestion(Set<Long> questionIdSet, Exam exam) {
        int num = 1;
        List<ExamQuestion> examQuestionList = new ArrayList<>();
        for(Long questionId : questionIdSet){

            //新增考试题目关系
            ExamQuestion examQuestion = new ExamQuestion();
            examQuestion.setQuestionId(questionId);
            examQuestion.setExamId(exam.getExamId());
            examQuestion.setQuestionOrder(num++);
            examQuestionList.add(examQuestion);
        }
        return saveBatch(examQuestionList);//批量新增 继承ServiceImpl
    }
}
